JavaScriptã«ãããããŒã¿ã¹ããªãŒã 管çã®æ·±æããéåæãžã§ãã¬ãŒã¿ãŒã®ãšã¬ã¬ã³ããªããã¯ãã¬ãã·ã£ãŒã¡ã«ããºã ãçšããŠãã·ã¹ãã éè² è·ãã¡ã¢ãªãªãŒã¯ãé²ãæ¹æ³ãåŠã³ãŸãããã
JavaScriptéåæãžã§ãã¬ãŒã¿ãŒã®ããã¯ãã¬ãã·ã£ãŒïŒã¹ããªãŒã ãããŒå¶åŸ¡ã®ç©¶æ¥µã¬ã€ã
ããŒã¿éçŽåã¢ããªã±ãŒã·ã§ã³ã®äžçã§ã¯ãããŒã¿ãœãŒã¹ãã³ã³ã·ã¥ãŒããŒãåŠçã§ãããããã¯ããã«éãæ å ±ãçæãããšããå žåçãªåé¡ã«ãã°ãã°çŽé¢ããŸããæ¶ç«ããŒã¹ãåºã®ã¹ããªã³ã¯ã©ãŒã«ã€ãªãã ç¶æ³ãæ³åããŠãã ãããæµéãå¶åŸ¡ãããã«ãããªããã°ã氎浞ãã®å€§æšäºã«ãªããŸãããœãããŠã§ã¢ã§ã¯ããã®æ°Ÿæ¿«ã¯ã¡ã¢ãªã®éè² è·ãã¢ããªã±ãŒã·ã§ã³ã®å¿ç忢ãæçµçãªã¯ã©ãã·ã¥ã«ã€ãªãããŸãããã®æ ¹æ¬çãªèª²é¡ã¯ããã¯ãã¬ãã·ã£ãŒãšåŒã°ããæŠå¿µã«ãã£ãŠç®¡çãããŠãããçŸä»£ã®JavaScriptã¯ãä»ã«é¡ãèŠãªããšã¬ã¬ã³ããªãœãªã¥ãŒã·ã§ã³ãããªãã¡éåæãžã§ãã¬ãŒã¿ãŒãæäŸããŸãã
ãã®å æ¬çãªã¬ã€ãã§ã¯ãJavaScriptã«ãããã¹ããªãŒã åŠçãšãããŒå¶åŸ¡ã®äžçãæ·±ãæãäžããŸããããã¯ãã¬ãã·ã£ãŒãšã¯äœãããªãå ç¢ãªã·ã¹ãã ãæ§ç¯ããããã«ãããäžå¯æ¬ ãªã®ãããããŠéåæãžã§ãã¬ãŒã¿ãŒãããã«å¯ŸåŠããããã®çŽæçã§çµã¿èŸŒã¿ã®ã¡ã«ããºã ãã©ã®ããã«æäŸããããæ¢ããŸããå€§èŠæš¡ãªãã¡ã€ã«ãåŠçããŠããå Žåã§ãããªã¢ã«ã¿ã€ã APIãå©çšããŠããå Žåã§ããè€éãªããŒã¿ãã€ãã©ã€ã³ãæ§ç¯ããŠããå Žåã§ãããã®ãã¿ãŒã³ãçè§£ããããšã¯ãéåæã³ãŒãã®æžãæ¹ãæ ¹æ¬çã«å€ããã§ãããã
1. ã³ã¢æŠå¿µã®è§£å
ãœãªã¥ãŒã·ã§ã³ãæ§ç¯ããåã«ããŸãããºã«ã®åºç€ãšãªãèŠçŽ ãçè§£ããå¿ èŠããããŸããã¹ããªãŒã ãããã¯ãã¬ãã·ã£ãŒããããŠéåæãžã§ãã¬ãŒã¿ãŒã®éæ³ãšããäž»èŠãªçšèªãæç¢ºã«ããŸãããã
ã¹ããªãŒã ãšã¯ïŒ
ã¹ããªãŒã ã¯ããŒã¿ã®å¡ã§ã¯ãªããæéã®çµéãšãšãã«å©çšå¯èœã«ãªãããŒã¿ã·ãŒã±ã³ã¹ã§ãã10ã®ã¬ãã€ãã®ãã¡ã€ã«å šäœãäžåºŠã«ã¡ã¢ãªã«èªã¿èŸŒã代ããã«ïŒããã¯ã¢ããªã±ãŒã·ã§ã³ãã¯ã©ãã·ã¥ãããå¯èœæ§ãé«ãã§ãããïŒãã¹ããªãŒã ãšããŠãå°ããã€èªã¿èŸŒãããšãã§ããŸãããã®æŠå¿µã¯ã³ã³ãã¥ãŒãã£ã³ã°ã«ãããŠæ®éçã§ãã
- ãã¡ã€ã«I/O: 倧容éã®ãã°ãã¡ã€ã«ãèªã¿èŸŒãã ãããããªããŒã¿ãæžã蟌ãã ãããŸãã
- ãããã¯ãŒã¯: ãã¡ã€ã«ãããŠã³ããŒãããããWebSocketããããŒã¿ãåä¿¡ãããããããªã³ã³ãã³ããã¹ããªãŒãã³ã°ãããããŸãã
- ããã»ã¹ééä¿¡: ããããã°ã©ã ã®åºåãå¥ã®ããã°ã©ã ã®å ¥åã«ãã€ãã§æž¡ããŸãã
ã¹ããªãŒã ã¯å¹çæ§ã«ãšã£ãŠäžå¯æ¬ ã§ãããæå°éã®ã¡ã¢ãªãããããªã³ãã§èšå€§ãªéã®ããŒã¿ãåŠçããããšãå¯èœã«ããŸãã
ããã¯ãã¬ãã·ã£ãŒãšã¯ïŒ
ããã¯ãã¬ãã·ã£ãŒãšã¯ãããŒã¿ã®æãŸããæµãã«éããæµæãŸãã¯åã®ããšã§ããããã¯ãé ãã³ã³ã·ã¥ãŒããŒãéããããã¥ãŒãµãŒã«ããããæžéããŠããïŒè¿œãã€ããªããã ãããšä¿¡å·ãéãããšãå¯èœã«ãããã£ãŒãããã¯ã¡ã«ããºã ã§ãã
å€å žçãªé¡æšã䜿ã£ãŠã¿ãŸãããïŒå·¥å Žã®ã¢ã»ã³ããªã©ã€ã³ã§ãã
- ãããã¥ãŒãµãŒã¯æåã®ã¹ããŒã·ã§ã³ã§ãé«éã§éšåãã³ã³ãã¢ãã«ãã«ä¹ããŸãã
- ã³ã³ã·ã¥ãŒããŒã¯æçµã¹ããŒã·ã§ã³ã§ãåéšåã«å¯ŸããŠé ããŠè©³çްãªçµã¿ç«ãŠãè¡ãå¿ èŠããããŸãã
ãããã¥ãŒãµãŒãéããããšãéšåãå±±ç©ã¿ã«ãªããã³ã³ã·ã¥ãŒããŒã«å°éããåã«ãã«ãããèœã¡ãŠããŸãã§ããããããã¯ããŒã¿æå€±ãšã·ã¹ãã é害ã§ããããã¯ãã¬ãã·ã£ãŒã¯ãã³ã³ã·ã¥ãŒããŒãã©ã€ã³ã«éãè¿ãä¿¡å·ã§ããã远ãã€ããŸã§ãããã¥ãŒãµãŒã«äžæåæ¢ããããã«äŒããŸããããã«ãããã·ã¹ãã å šäœãæãé ãã³ã³ããŒãã³ãã®ããŒã¹ã§åäœããéè² è·ãé²ããŸãã
ããã¯ãã¬ãã·ã£ãŒããªãå Žåã以äžã®ãªã¹ã¯ããããŸã:
- ç¡å¶éã®ãããã¡ãªã³ã°: ããŒã¿ãã¡ã¢ãªã«èç©ãããé«ãRAM䜿çšéãšã¯ã©ãã·ã¥ã®å¯èœæ§ã«ã€ãªãããŸãã
- ããŒã¿æå€±: ãããã¡ããªãŒããŒãããŒããå ŽåãããŒã¿ã倱ãããå¯èœæ§ããããŸãã
- ã€ãã³ãã«ãŒãã®ãããã¯: Node.jsã§ã¯ãéè² è·ç¶æ ã®ã·ã¹ãã ãã€ãã³ãã«ãŒãããããã¯ããã¢ããªã±ãŒã·ã§ã³ãå¿çããªããªãå¯èœæ§ããããŸãã
ã¯ã€ãã¯ãªãã¬ãã·ã¥: ãžã§ãã¬ãŒã¿ãŒãšéåæã€ãã¬ãŒã¿ãŒ
çŸä»£ã®JavaScriptã«ãããããã¯ãã¬ãã·ã£ãŒã®è§£æ±ºçã¯ãå®è¡ãäžæåæ¢ããã³åéã§ããæ©èœã«ãããŸããããããç°¡åã«åŸ©ç¿ããŠã¿ãŸãããã
ãžã§ãã¬ãŒã¿ãŒ (`function*`): ãããã¯ãçµäºããåŸã§åå ¥ã§ããç¹æ®ãªé¢æ°ã§ãã`yield`ããŒã¯ãŒãã䜿çšããŠãäžæåæ¢ãããå€ãè¿ããŸããåŒã³åºãå ã¯ã次ã®å€ãååŸããããã«ãã€é¢æ°ã®å®è¡ãåéããããæ±ºå®ã§ããŸããããã«ãããåæããŒã¿ã«å¯ŸããŠãªã³ããã³ãã®ãã«ããŒã¹ã·ã¹ãã ãäœæãããŸãã
éåæã€ãã¬ãŒã¿ãŒ (`Symbol.asyncIterator`): ããã¯ãéåæããŒã¿ãœãŒã¹ãå埩åŠçããæ¹æ³ãå®çŸ©ãããããã³ã«ã§ãããªããžã§ã¯ãã¯ã`Symbol.asyncIterator`ãšããããŒãæã€ã¡ãœãããããããã®ã¡ãœããã`next()`ã¡ãœãããæã€ãªããžã§ã¯ããè¿ãå Žåãéåæã€ãã©ãã«ã§ãããã®`next()`ã¡ãœããã¯ã`{ value, done }`ã«è§£æ±ºããPromiseãè¿ããŸãã
éåæãžã§ãã¬ãŒã¿ãŒ (`async function*`): ããã§ãã¹ãŠãçµã³ã€ããŸããéåæãžã§ãã¬ãŒã¿ãŒã¯ããžã§ãã¬ãŒã¿ãŒã®äžæåæ¢ã®åäœãšPromiseã®éåææ§ãçµã¿åããããã®ã§ããæéã®çµéãšãšãã«å°çããããŒã¿ã®ã¹ããªãŒã ã衚ãã®ã«æé©ãªããŒã«ã§ãã
éåæãžã§ãã¬ãŒã¿ãŒã¯ã`.next()`ã®åŒã³åºããšPromiseã®è§£æ±ºãåŸ ã€è€éããæœè±¡åãã匷åãª`for await...of`ã«ãŒãã䜿çšããŠæ¶è²»ããŸãã
async function* countToThree() {
yield 1; // Pause and yield 1
await new Promise(resolve => setTimeout(resolve, 1000)); // Asynchronously wait
yield 2; // Pause and yield 2
await new Promise(resolve => setTimeout(resolve, 1000));
yield 3; // Pause and yield 3
}
async function main() {
console.log("Starting consumption...");
for await (const number of countToThree()) {
console.log(number); // This will log 1, then 2 after 1s, then 3 after another 1s
}
console.log("Finished consumption.");
}
main();
éèŠãªæŽå¯ã¯ã`for await...of`ã«ãŒãããžã§ãã¬ãŒã¿ãŒããå€ã*ãã«*ããããšã§ããã«ãŒãå ã®ã³ãŒããçŸåšã®å€ã®å®è¡ãå®äºãããŸã§ã次ã®å€ãèŠæ±ããããšã¯ãããŸããããã®æ¬è³ªçãªãã«ããŒã¹ã®æ§è³ªããèªåããã¯ãã¬ãã·ã£ãŒã®ç§å¯ã§ãã
2. åé¡ã®å³è§£: ããã¯ãã¬ãã·ã£ãŒãªãã®ã¹ããªãŒãã³ã°
ãã®ãœãªã¥ãŒã·ã§ã³ã®ç䟡ãçè§£ããããã«ãäžè¬çã§ã¯ãããã®ã®æ¬ é¥ã®ãããã¿ãŒã³ãèŠãŠã¿ãŸããããéåžžã«é«éãªããŒã¿ãœãŒã¹ïŒãããã¥ãŒãµãŒïŒãšãé ãããŒã¿ããŒã¹ãžã®æžã蟌ã¿ãã¬ãŒãå¶éãããAPIã®åŒã³åºããè¡ããããªãäœéãªããŒã¿ããã»ããµãŒïŒã³ã³ã·ã¥ãŒããŒïŒããããšæ³åããŠãã ããã
以äžã«ãåŸæ¥ã®ã€ãã³ããšããã¿ãŒãŸãã¯ã³ãŒã«ããã¯åœ¢åŒã®ã¢ãããŒãïŒããã·ã¥ããŒã¹ã·ã¹ãã ïŒã䜿çšããã·ãã¥ã¬ãŒã·ã§ã³ã瀺ããŸãã
// Represents a very fast data source
class FastProducer {
constructor() {
this.listeners = [];
}
onData(listener) {
this.listeners.push(listener);
}
start() {
let id = 0;
// Produce data every 10 milliseconds
this.interval = setInterval(() => {
const data = { id: id++, timestamp: Date.now() };
console.log(`PRODUCER: Emitting item ${data.id}`);
this.listeners.forEach(listener => listener(data));
}, 10);
}
stop() {
clearInterval(this.interval);
}
}
// Represents a slow consumer (e.g., writing to a slow network service)
async function slowConsumer(data) {
console.log(` CONSUMER: Starting to process item ${data.id}...`);
// Simulate a slow I/O operation taking 500 milliseconds
await new Promise(resolve => setTimeout(resolve, 500));
console.log(` CONSUMER: ...Finished processing item ${data.id}`);
}
// --- Let's run the simulation ---
const producer = new FastProducer();
const dataBuffer = [];
producer.onData(data => {
console.log(`Received item ${data.id}, adding to buffer.`);
dataBuffer.push(data);
// A naive attempt to process
// slowConsumer(data); // This would block new events if we awaited it
});
producer.start();
// Let's inspect the buffer after a short time
setTimeout(() => {
producer.stop();
console.log(`\n--- After 2 seconds ---`);
console.log(`Buffer size is: ${dataBuffer.length}`);
console.log(`Producer created around 200 items, but the consumer would have only processed 4.`);
console.log(`The other 196 items are sitting in memory, waiting.`);
}, 2000);
What's Happening Here?
The producer is firing off data every 10ms. The consumer takes 500ms to process a single item. The producer is 50 times faster than the consumer!
ãã®ããã·ã¥ããŒã¹ã®ã¢ãã«ã§ã¯ããããã¥ãŒãµãŒã¯ã³ã³ã·ã¥ãŒããŒã®ç¶æ ããŸã£ããèªèããŠããŸããããã ããŒã¿ãããã·ã¥ãç¶ããŸããç§ãã¡ã®ã³ãŒãã¯ãåä¿¡ããããŒã¿ãé å`dataBuffer`ã«è¿œå ããã ãã§ããããã2ç§ã®éã«ããã®ãããã¡ãŒã«ã¯çŽ200åã®ã¢ã€ãã ãå«ãŸããŠããŸããäœæéãå®è¡ãããå®éã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ããã®ãããã¡ãŒã¯ç¡éã«å¢å€§ããå©çšå¯èœãªãã¹ãŠã®ã¡ã¢ãªãæ¶è²»ããŠããã»ã¹ãã¯ã©ãã·ã¥ãããŠããŸãã§ããããããããããæãå±éºãªåœ¢ã®ããã¯ãã¬ãã·ã£ãŒåé¡ã§ãã
3. 解決ç: éåæãžã§ãã¬ãŒã¿ãŒã«ããåºæã®ããã¯ãã¬ãã·ã£ãŒ
ã§ã¯ãåãã·ããªãªãéåæãžã§ãã¬ãŒã¿ãŒã䜿ã£ãŠãªãã¡ã¯ã¿ãªã³ã°ããŠã¿ãŸãããããããã¥ãŒãµãŒããããã·ã£ãŒãããããã«ãã§ãããã®ãžãšå€æããŸãã
äžå¿ãšãªãã¢ã€ãã¢ã¯ãããŒã¿ãœãŒã¹ã`async function*`ã§ã©ããããããšã§ãããã®åŸãã³ã³ã·ã¥ãŒããŒã¯`for await...of`ã«ãŒãã䜿çšããŠãæºåãã§ãããšãã«ã®ã¿ããŒã¿ããã«ããŸãã
// PRODUCER: A data source wrapped in an async generator
async function* createFastProducer() {
let id = 0;
while (true) {
// Simulate a fast data source creating an item
await new Promise(resolve => setTimeout(resolve, 10));
const data = { id: id++, timestamp: Date.now() };
console.log(`PRODUCER: Yielding item ${data.id}`);
yield data; // Pause until the consumer requests the next item
}
}
// CONSUMER: A slow process, just like before
async function slowConsumer(data) {
console.log(` CONSUMER: Starting to process item ${data.id}...`);
// Simulate a slow I/O operation taking 500 milliseconds
await new Promise(resolve => setTimeout(resolve, 500));
console.log(` CONSUMER: ...Finished processing item ${data.id}`);
}
// --- The main execution logic ---
async function main() {
const producer = createFastProducer();
// The magic of `for await...of`
for await (const data of producer) {
await slowConsumer(data);
}
}
main();
å®è¡ãããŒãåæããŠã¿ãã
ãã®ã³ãŒããå®è¡ãããšãåçã«ç°ãªãåºåã衚瀺ãããŸããæ¬¡ã®ãããªè¡šç€ºã«ãªãã§ãããã
PRODUCER: Yielding item 0 CONSUMER: Starting to process item 0... CONSUMER: ...Finished processing item 0 PRODUCER: Yielding item 1 CONSUMER: Starting to process item 1... CONSUMER: ...Finished processing item 1 PRODUCER: Yielding item 2 CONSUMER: Starting to process item 2... ...
å®ç§ãªåæã«æ³šç®ããŠãã ããããããã¥ãŒãµãŒã¯ãã³ã³ã·ã¥ãŒããŒãåã®ã¢ã€ãã ã®åŠçãå®å šã«çµãã*åŸã§ãªããã°*ãæ°ããã¢ã€ãã ãçæããŸããããããã¡ãŒãè¥å€§åããããšããã¡ã¢ãªãªãŒã¯ããããŸãããããã¯ãã¬ãã·ã£ãŒã¯èªåçã«éæãããŸãã
ãããæ©èœããçç±ã®æ®µéçãªå èš³ã¯æ¬¡ã®ãšããã§ãã
- `for await...of`ã«ãŒããéå§ãããèå°è£ã§`producer.next()`ãåŒã³åºãããæåã®ã¢ã€ãã ãèŠæ±ãããŸãã
- `createFastProducer`颿°ãå®è¡ãéå§ããŸãã10ããªç§åŸ æ©ããã¢ã€ãã 0ã®`data`ãäœæãã`yield data`ã«å°éããŸãã
- ãžã§ãã¬ãŒã¿ãŒã¯ãã®å®è¡ãäžæåæ¢ããçæãããå€ïŒ`{ value: data, done: false }`ïŒã§è§£æ±ºããPromiseãè¿ããŸãã
- `for await...of`ã«ãŒãã¯å€ãåãåããŸãããã®æåã®ããŒã¿ã¢ã€ãã ã§ã«ãŒãæ¬äœã®å®è¡ãéå§ãããŸãã
- `await slowConsumer(data)`ãåŒã³åºããŸããããã¯å®äºããã®ã«500ããªç§ããããŸãã
- ãããæãéèŠãªéšåã§ã: `for await...of`ã«ãŒãã¯ã`await slowConsumer(data)`ã®Promiseã解決ããããŸã§ãå床`producer.next()`ãåŒã³åºããŸããããããã¥ãŒãµãŒã¯`yield`ã¹ããŒãã¡ã³ãã§äžæåæ¢ãããŸãŸã§ãã
- 500ããªç§åŸã`slowConsumer`ãçµäºããŸãããã®ã€ãã¬ãŒã·ã§ã³ã®ã«ãŒãæ¬äœã¯å®äºã§ãã
- ãããŠããŸãã«ãã®æç¹ã§ã`for await...of`ã«ãŒãã¯å床`producer.next()`ãåŒã³åºããæ¬¡ã®ã¢ã€ãã ãèŠæ±ããŸãã
- `createFastProducer`颿°ã¯ãäžæããå Žæããåéãã`while`ã«ãŒããç¶è¡ããã¢ã€ãã 1ã®ãµã€ã¯ã«ãåã³éå§ããŸãã
ã³ã³ã·ã¥ãŒããŒã®åŠçé床ãããããã¥ãŒãµãŒã®çæé床ãçŽæ¥å¶åŸ¡ããŸããããã¯ãã«ããŒã¹ã·ã¹ãã ã§ãããçŸä»£ã®JavaScriptã«ããããšã¬ã¬ã³ããªãããŒå¶åŸ¡ã®åºç€ã§ãã
4. é«åºŠãªãã¿ãŒã³ãšå®äžçã§ã®ãŠãŒã¹ã±ãŒã¹
éåæãžã§ãã¬ãŒã¿ãŒã®çã®åã¯ãè€éãªããŒã¿å€æãå®è¡ããããã«ããããããã€ãã©ã€ã³ã«æ§æãå§ãããšãã«çºæ®ãããŸãã
ã¹ããªãŒã ã®ãã€ãåŠçãšå€æ
Unixã®ã³ãã³ãã©ã€ã³ã§ã³ãã³ãããã€ãåŠçã§ããã®ãšåãããã«ïŒäŸïŒ`cat log.txt | grep 'ERROR' | wc -l`ïŒãéåæãžã§ãã¬ãŒã¿ãŒãé£çµããããšãã§ããŸãããã©ã³ã¹ãã©ãŒããŒãšã¯ãåã«å¥ã®éåæã€ãã©ãã«ãå ¥åãšããŠåãåãã倿ãããããŒã¿ãçæããéåæãžã§ãã¬ãŒã¿ãŒã®ããšã§ãã
å¶æ¥ããŒã¿ã®å€§å®¹éCSVãã¡ã€ã«ãåŠçããŠãããšæ³åããŠã¿ãŸãããããã¡ã€ã«ãèªã¿èŸŒã¿ãåè¡ãããŒã¹ããé«é¡ãªååŒããã£ã«ã¿ãªã³ã°ããŠãããŒã¿ããŒã¹ã«ä¿åããããšèããŠããŸãã
const fs = require('fs');
const { once } = require('events');
// PRODUCER: Reads a large file line by line
async function* readFileLines(filePath) {
const readable = fs.createReadStream(filePath, { encoding: 'utf8' });
let buffer = '';
readable.on('data', chunk => {
buffer += chunk;
let newlineIndex;
while ((newlineIndex = buffer.indexOf('\n')) >= 0) {
const line = buffer.slice(0, newlineIndex);
buffer = buffer.slice(newlineIndex + 1);
readable.pause(); // Explicitly pause Node.js stream for backpressure
yield line;
}
});
readable.on('end', () => {
if (buffer.length > 0) {
yield buffer; // Yield the last line if no trailing newline
}
});
// A simplified way to wait for the stream to finish or error
await once(readable, 'close');
}
// TRANSFORMER 1: Parses CSV lines into objects
async function* parseCSV(lines) {
for await (const line of lines) {
const [id, product, amount] = line.split(',');
if (id && product && amount) {
yield { id, product, amount: parseFloat(amount) };
}
}
}
// TRANSFORMER 2: Filters for high-value transactions
async function* filterHighValue(transactions, minValue) {
for await (const tx of transactions) {
if (tx.amount >= minValue) {
yield tx;
}
}
}
// CONSUMER: Saves the final data to a slow database
async function saveToDatabase(transaction) {
console.log(`Saving transaction ${transaction.id} with amount ${transaction.amount} to DB...`);
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate slow DB write
}
// --- The Composed Pipeline ---
async function processSalesFile(filePath) {
const lines = readFileLines(filePath);
const transactions = parseCSV(lines);
const highValueTxs = filterHighValue(transactions, 1000);
console.log("Starting ETL pipeline...");
for await (const tx of highValueTxs) {
await saveToDatabase(tx);
}
console.log("Pipeline finished.");
}
// Create a dummy large CSV file for testing
// fs.writeFileSync('sales.csv', ...);
// processSalesFile('sales.csv');
ãã®äŸã§ã¯ãããã¯ãã¬ãã·ã£ãŒããã§ãŒã³å šäœã«äŒæããŸãã`saveToDatabase`ãæãé ãéšåã§ãããã®`await`ãæåŸã®`for await...of`ã«ãŒããäžæåæ¢ãããŸããããã«ããã`filterHighValue`ãäžæåæ¢ãã`parseCSV`ããã®ã¢ã€ãã èŠæ±ã忢ãããããã«`readFileLines`ããã®ã¢ã€ãã èŠæ±ã忢ãããæçµçã«ã¯Node.jsã®ãã¡ã€ã«ã¹ããªãŒã ã«ãã£ã¹ã¯ããã®ç©ççãª`pause()`èªã¿èŸŒã¿ãæç€ºããŸããã·ã¹ãã å šäœã¯ãéåæã€ãã¬ãŒã·ã§ã³ã®ã·ã³ãã«ãªãã«ã¡ã«ããºã ã«ãã£ãŠèª¿æŽãããæå°éã®ã¡ã¢ãªã䜿çšããŠåæããŠåäœããŸãã
ãšã©ãŒã gracefully ã«åŠçãã
ãšã©ãŒåŠçã¯ç°¡åã§ããã³ã³ã·ã¥ãŒããŒã®ã«ãŒãã`try...catch`ãããã¯ã§å²ãããšãã§ããŸããäžæµã®ãžã§ãã¬ãŒã¿ãŒã®ããããã§ãšã©ãŒãã¹ããŒãããå Žåãããã¯äžæµã«äŒæããã³ã³ã·ã¥ãŒããŒã«ãã£ãŠææãããŸãã
async function* errorProneGenerator() {
yield 1;
yield 2;
throw new Error("Something went wrong in the generator!");
yield 3; // This will never be reached
}
async function main() {
try {
for await (const value of errorProneGenerator()) {
console.log("Received:", value);
}
} catch (err) {
console.error("Caught an error:", err.message);
}
}
main();
// Output:
// Received: 1
// Received: 2
// Caught an error: Something went wrong in the generator!
`try...finally`ã«ãããªãœãŒã¹ã¯ãªãŒã³ã¢ãã
ã³ã³ã·ã¥ãŒããŒãåŠçãæ©ãã«åæ¢ããããšïŒäŸïŒ`break`ã¹ããŒãã¡ã³ãã䜿çšïŒã決å®ããå Žåãã©ããªãã§ããããïŒãžã§ãã¬ãŒã¿ãŒã¯ãã¡ã€ã«ãã³ãã«ãããŒã¿ããŒã¹æ¥ç¶ã®ãããªéããããªãœãŒã¹ãä¿æãããŸãŸã«ãªãå¯èœæ§ããããŸãããžã§ãã¬ãŒã¿ãŒå ã®`finally`ãããã¯ã¯ãã¯ãªãŒã³ã¢ããã«æé©ãªå Žæã§ãã
`for await...of`ã«ãŒããéäžã§çµäºããå ŽåïŒ`break`ã`return`ããŸãã¯ãšã©ãŒçµç±ã§ïŒããžã§ãã¬ãŒã¿ãŒã®`.return()`ã¡ãœãããèªåçã«åŒã³åºãããŸããããã«ããããžã§ãã¬ãŒã¿ãŒã¯`finally`ãããã¯ã«ãžã£ã³ãããã¯ãªãŒã³ã¢ããã¢ã¯ã·ã§ã³ãå®è¡ã§ããŸãã
async function* fileReaderWithCleanup(filePath) {
let fileHandle;
try {
console.log("GENERATOR: Opening file...");
fileHandle = await fs.promises.open(filePath, 'r');
// ... logic to yield lines from the file ...
yield 'line 1';
yield 'line 2';
yield 'line 3';
} finally {
if (fileHandle) {
console.log("GENERATOR: Closing file handle.");
await fileHandle.close();
}
}
}
async function main() {
for await (const line of fileReaderWithCleanup('my-file.txt')) {
console.log("CONSUMER:", line);
if (line === 'line 2') {
console.log("CONSUMER: Breaking the loop early.");
break; // Exit the loop
}
}
}
main();
// Output:
// GENERATOR: Opening file...
// CONSUMER: line 1
// CONSUMER: line 2
// CONSUMER: Breaking the loop early.
// GENERATOR: Closing file handle.
5. ä»ã®ããã¯ãã¬ãã·ã£ãŒã¡ã«ããºã ãšã®æ¯èŒ
éåæãžã§ãã¬ãŒã¿ãŒã¯ãJavaScriptãšã³ã·ã¹ãã ã«ãããŠããã¯ãã¬ãã·ã£ãŒãåŠçããå¯äžã®æ¹æ³ã§ã¯ãããŸãããä»ã®äººæ°ã®ããã¢ãããŒããšæ¯èŒããŠãããããã©ã®ããã«æ©èœããããçè§£ããããšã¯æçšã§ãã
Node.jsã¹ããªãŒã ïŒ`.pipe()`ããã³`pipeline`ïŒ
Node.jsã«ã¯ãé·å¹Žã«ãããããã¯ãã¬ãã·ã£ãŒãåŠçããŠãã匷åãªçµã¿èŸŒã¿Streams APIããããŸãã`readable.pipe(writable)`ã䜿çšãããšãNode.jsã¯å éšãããã¡ãŒãš`highWaterMark`èšå®ã«åºã¥ããŠããŒã¿ã®ãããŒã管çããŸããããã¯ãããã¯ãã¬ãã·ã£ãŒã¡ã«ããºã ãçµã¿èŸŒãŸããã€ãã³ãé§ååãããã·ã¥ããŒã¹ã®ã·ã¹ãã ã§ãã
- è€éã: Node.js Streams APIã¯ãç¹ã«ã«ã¹ã¿ã 倿ã¹ããªãŒã ã®å Žåãæ£ããå®è£ ããã®ãéåžžã«è€éã§ãããšãããŠããŸããã¯ã©ã¹ã®æ¡åŒµããå éšç¶æ ãšã€ãã³ãïŒ`'data'`ã`'end'`ã`'drain'`ïŒã®ç®¡çã䌎ããŸãã
- ãšã©ãŒåŠç: `.pipe()`ã§ã®ãšã©ãŒåŠçã¯åä»ã§ãã1ã€ã®ã¹ããªãŒã ã§ãšã©ãŒãçºçããŠãããã€ãã©ã€ã³å ã®ä»ã®ã¹ããªãŒã ãèªåçã«ç Žæ£ãããããã§ã¯ãªãããã§ãããã®ãããããå ç¢ãªä»£æ¿ææ®µãšããŠ`stream.pipeline`ãå°å ¥ãããŸããã
- å¯èªæ§: éåæãžã§ãã¬ãŒã¿ãŒã¯ãããåæçã«èŠããã³ãŒãã«ã€ãªããããšãå€ããç¹ã«è€éãªå€æã®å Žåãèªã¿ããããçè§£ãããããšèšããŸãã
Node.jsã§ã®é«æ§èœãªäœã¬ãã«I/Oã«ã¯ããã€ãã£ãã®Streams APIã¯äŸç¶ãšããŠåªããéžæè¢ã§ããããããã¢ããªã±ãŒã·ã§ã³ã¬ãã«ã®ããžãã¯ãããŒã¿å€æã§ã¯ãéåæãžã§ãã¬ãŒã¿ãŒãããã·ã³ãã«ã§ãšã¬ã¬ã³ããªéçºäœéšãæäŸããããšããããããŸãã
ãªã¢ã¯ãã£ãããã°ã©ãã³ã°ïŒRxJSïŒ
RxJSã®ãããªã©ã€ãã©ãªã¯Observableã®æŠå¿µã䜿çšããŸããNode.jsã¹ããªãŒã ãšåæ§ã«ãObservableã¯äž»ã«ããã·ã¥ããŒã¹ã®ã·ã¹ãã ã§ãããããã¥ãŒãµãŒïŒObservableïŒãå€ãæŸåºããã³ã³ã·ã¥ãŒããŒïŒObserverïŒããããã«åå¿ããŸããRxJSã«ãããããã¯ãã¬ãã·ã£ãŒã¯èªåçã§ã¯ãããŸããã`buffer`ã`throttle`ã`debounce`ãªã©ã®æ§ã ãªãªãã¬ãŒã¿ãŒãã«ã¹ã¿ã ã¹ã±ãžã¥ãŒã©ãŒã䜿çšããŠãæç€ºçã«ç®¡çããå¿ èŠããããŸãã
- ãã©ãã€ã : RxJSã¯ãè€éãªéåæã€ãã³ãã¹ããªãŒã ãæ§æããã³ç®¡çããããã®åŒ·åãªé¢æ°åããã°ã©ãã³ã°ãã©ãã€ã ãæäŸããŸããUIã€ãã³ãåŠçã®ãããªã·ããªãªã«ã¯éåžžã«åŒ·åã§ãã
- åŠç¿æ²ç·: RxJSã¯ããã®èšå€§ãªæ°ã®ãªãã¬ãŒã¿ãŒãšãªã¢ã¯ãã£ãããã°ã©ãã³ã°ã«å¿ èŠãªæèã®å€åã®ãããæ¥ãªåŠç¿æ²ç·ãæã£ãŠããŸãã
- ãã«å¯Ÿããã·ã¥: éèŠãªéãã¯äŸç¶ãšããŠæ®ã£ãŠããŸããéåæãžã§ãã¬ãŒã¿ãŒã¯æ ¹æ¬çã«ãã«ããŒã¹ã§ããïŒã³ã³ã·ã¥ãŒããŒãå¶åŸ¡ããïŒãObservableã¯ããã·ã¥ããŒã¹ã§ãïŒãããã¥ãŒãµãŒãå¶åŸ¡ããã³ã³ã·ã¥ãŒããŒã¯ãã¬ãã·ã£ãŒã«åå¿ããªããã°ãªããŸããïŒã
éåæãžã§ãã¬ãŒã¿ãŒã¯ãã€ãã£ãèšèªæ©èœã§ãããå æ¬çãªã©ã€ãã©ãªRxJSãå¿ èŠãšãããããããªãå€ãã®ããã¯ãã¬ãã·ã£ãŒåé¡ã«å¯ŸããŠã軜éã§äŸåé¢ä¿ã®ãªãéžæè¢ãšãªããŸãã
çµè«: ãã«ãåãå ¥ããã
ããã¯ãã¬ãã·ã£ãŒã¯ãªãã·ã§ã³ã®æ©èœã§ã¯ãããŸãããå®å®ãããã¹ã±ãŒã©ãã«ã§ãã¡ã¢ãªå¹çã®è¯ãããŒã¿åŠçã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®åºæ¬çãªèŠä»¶ã§ãããããæ ãããšã¯ãã·ã¹ãã é害ã®å ãšãªããŸãã
é·å¹ŽãJavaScriptéçºè ã¯ãã¹ããªãŒã ã®ãããŒå¶åŸ¡ã管çããããã«ãè€éãªã€ãã³ãããŒã¹ã®APIããµãŒãããŒãã£ã©ã€ãã©ãªã«é Œã£ãŠããŸãããéåæãžã§ãã¬ãŒã¿ãŒãš`for await...of`æ§æã®å°å ¥ã«ãããç§ãã¡ã¯ä»ãèšèªã«çŽæ¥çµã¿èŸŒãŸãã匷åã§ãã€ãã£ããªããããŠçŽæçãªããŒã«ãæã«å ¥ããŸããã
ããã·ã¥ããŒã¹ãããã«ããŒã¹ã®ã¢ãã«ã«ç§»è¡ããããšã§ãéåæãžã§ãã¬ãŒã¿ãŒã¯åºæã®ããã¯ãã¬ãã·ã£ãŒãæäŸããŸããã³ã³ã·ã¥ãŒããŒã®åŠçé床ãèªç¶ã«ãããã¥ãŒãµãŒã®éåºŠãæ±ºå®ãããã®çµæã次ã®ãããªã³ãŒããçãŸããŸãã
- ã¡ã¢ãªã»ãŒã: ç¡å¶éã®ãããã¡ãŒãæé€ããã¡ã¢ãªäžè¶³ã«ããã¯ã©ãã·ã¥ãé²ããŸãã
- å¯èªæ§: è€éãªéåæããžãã¯ãã·ã³ãã«ã§é 次å®è¡ã«èŠããã«ãŒãã«å€æããŸãã
- æ§æå¯èœ: ãšã¬ã¬ã³ãã§åå©çšå¯èœãªããŒã¿å€æãã€ãã©ã€ã³ã®äœæãå¯èœã«ããŸãã
- å ç¢æ§: æšæºã®`try...catch...finally`ãããã¯ã§ãšã©ãŒåŠçãšãªãœãŒã¹ç®¡çãç°¡çŽ åããŸãã
次åããã¡ã€ã«ãAPIããŸãã¯ãã®ä»ã®éåæãœãŒã¹ããããŒã¿ã¹ããªãŒã ãåŠçããå¿ èŠããããšãã¯ãæåãããã¡ãªã³ã°ãè€éãªã³ãŒã«ããã¯ã«æã䌞ã°ããªãã§ãã ãããéåæãžã§ãã¬ãŒã¿ãŒã®ãã«ããŒã¹ã®ãšã¬ã¬ã³ã¹ãåãå ¥ããŸããããããã¯ãéåæã³ãŒããããã¯ãªãŒã³ã«ãããå®å šã«ããããŠãã匷åã«ããçŸä»£çãªJavaScriptãã¿ãŒã³ã§ãã